/*
 * Copyright (c) 2006-2021, xxxx Development Team
 *
 *
 * Change Logs:
 * Date           Author       Version      Notes
 * 2022-11-22     TSL          v0.1         first version
 */

/* 头文件 ---------------------------------------------------------------------*/
#include "fsl_single_key.h"
#include <stddef.h>

/* 宏定义 ---------------------------------------------------------------------*/
#define KEY_RELEASE              0
#define KEY_PRESS                1
#define KEY_SCAN_LOOP_PERIOD_MS  10
#define KEY_LONG_PRESS_THV_MS    1000 /* 触发长按动作的时间 */
#define KEY_VALID_GAP_THV_MS     100  /* 若支持双击间隔建议大于80，若支持快速单击，需要调小 */

#define GET_TICK()          s_tick_ms

#if FSL_SINGLE_KEY_LOOP_CALL_MODE == FSL_SINGLE_KEY_LOOP_GAP_TICK
#define UPDATE_TICK(_tick_) s_tick_ms += _tick_
#elif FSL_SINGLE_KEY_LOOP_CALL_MODE == FSL_SINGLE_KEY_LOOP_SYS_TICK
#define UPDATE_TICK(_tick_) s_tick_ms = _tick_
#endif

/* 类型定义 -------------------------------------------------------------------*/

/* 函数声明 -------------------------------------------------------------------*/

/* 变量声明 -------------------------------------------------------------------*/
#if FSL_SINGLE_KEY_INDICATE_MODE == FSL_SINGLE_KEY_INDICATE_BRIEF
static void (*key_indicate_callback)(void) = NULL;
#endif
static uint8_t s_key_valid = 0;
static uint32_t s_tick_ms = 0;
static LIST_HEAD(dev_list_head);

/*
 * 函数说明
 */
void fsl_single_key_init_dev(key_dev_t *dev)
{
    dev->click_count = 0xFF;             // 点击次数（内部使用，初始化为0xFF）
    dev->press_time = 0;                 // 按下时间（内部使用，初始化为0）
    dev->release_time = 0;               // 释放时间（内部使用，初始化为0）
    dev->pin_last_state = KEY_RELEASE;   // 上次引脚状态（内部使用，初始化为KEY_RELEASE）
    dev->pin_curr_state_debounce = 0xFF; // 当前引脚去痘后的状态（内部使用，初始化为无效值）
    dev->key_value = KEY_NONE_VAL;       // 检测到的按键状态（内部使用，初始化为KEY_NONE_VAL）
    dev->key_value_out = KEY_NONE_VAL;   // 按键状态对外输出变量, 初始化为KEY_NONE_VAL
    dev->hw_pin_is_press = NULL;         // 查询当前硬件引脚是否按下接口
    list_init(&dev->list);
}

/*
 * 函数说明
 */
void fsl_single_key_register_dev(key_dev_t *dev)
{
    if (dev->hw_pin_is_press == NULL)
    {
        return;
    }
    
    list_insert_tail(&dev_list_head, &dev->list);
}

/*
 * 函数说明
 */
#if FSL_SINGLE_KEY_LOOP_CALL_MODE == FSL_SINGLE_KEY_LOOP_GAP_TICK
void fsl_single_key_loop(uint8_t loop_gap_ms)
{
    // 更新内部时基
    UPDATE_TICK(loop_gap_ms);
#elif FSL_SINGLE_KEY_LOOP_CALL_MODE == FSL_SINGLE_KEY_LOOP_SYS_TICK
void fsl_single_key_loop(uint32_t system_tick_ms)
{
    // 更新内部时基
    UPDATE_TICK(system_tick_ms);
#endif

    // 按键扫描周期控制
    static uint32_t s_tick_start = 0;
    uint32_t tick_now = GET_TICK();
    if ((uint32_t)(tick_now - s_tick_start) < KEY_SCAN_LOOP_PERIOD_MS)
    {
        return;
    }
    s_tick_start = tick_now;
    
    // 扫描所有按键实例
    uint8_t pin_state_curr, key_is_ready = 0, scan_is_busy = 0;
    static list_obj_t* node;
    static key_dev_t *dev;
    list_for_each(node, &dev_list_head)
    {
        dev = list_entry(node, key_dev_t, list);
        pin_state_curr = dev->hw_pin_is_press();
        // 去抖
        if (dev->pin_curr_state_debounce != pin_state_curr)
        {
            dev->pin_curr_state_debounce = pin_state_curr;
        }
        // 扫描
        else
        {
            if (dev->click_count == 0xFF)
            {
                if(dev->pin_curr_state_debounce == KEY_RELEASE)
                {
                    dev->click_count = 0;
                    dev->press_time = 0;
                    dev->release_time = 0;
                    if (dev->pin_last_state == KEY_PRESS)
                    {
                        dev->pin_last_state = KEY_RELEASE;
                        dev->key_value = KEY_LONG_RELEASE_VAL;
                    }
                }
            }
            else
            {
                if (dev->pin_curr_state_debounce == KEY_PRESS)
                {
                    if (dev->pin_last_state == KEY_RELEASE)
                    {
                        dev->click_count++;
                        dev->press_time = 0;
                        dev->release_time = 0;
                    }
                    else
                    {
                        dev->press_time++;
                        if(dev->press_time >= (KEY_LONG_PRESS_THV_MS/KEY_SCAN_LOOP_PERIOD_MS))
                        {
                            dev->key_value = KEY_LONG_PRESS_VAL;
                            dev->click_count = 0xFF;
                            dev->press_time = 0;
                        }
                    }
                }
                else if (dev->click_count > 0)
                {
                    dev->release_time++;
                    if(dev->release_time >= (KEY_VALID_GAP_THV_MS/KEY_SCAN_LOOP_PERIOD_MS))
                    {
                        if(dev->click_count == 1)
                        {
                            dev->key_value = KEY_CLICK_VAL;
                        }
                        else if(dev->click_count >= 2) //<-大于2击都定为双击(可选；若支持三击、四击等再此处修改) //if(dev->click_count == 2)
                        {
                            dev->key_value = KEY_D_CLICK_VAL;
                        }
                        dev->click_count = 0;
                        dev->press_time = 0;
                        dev->release_time = 0;
                    }
                }
                dev->pin_last_state = dev->pin_curr_state_debounce;
            }
        }
        // 准备同步输出
        if (dev->key_value != KEY_NONE_VAL)
            key_is_ready = 1;
        if (dev->press_time != 0)
            scan_is_busy = 1;
    }

    // 所有按键实例同步更新输出状态
    if ((key_is_ready == 1) && (scan_is_busy == 0))
    {
        list_for_each(node, &dev_list_head)
        {
            dev = list_entry(node, key_dev_t, list);
            if (dev->key_value != KEY_NONE_VAL)
            {
                dev->key_value_out = dev->key_value;
                dev->key_value = KEY_NONE_VAL;
                s_key_valid = 1;
            }
        }
#if FSL_SINGLE_KEY_INDICATE_MODE == FSL_SINGLE_KEY_INDICATE_BRIEF
        if ((s_key_valid != 0) && (key_indicate_callback != NULL))
        {
            key_indicate_callback();
        }
#endif
    }
}

/*
 * 函数说明
 */
uint8_t fsl_single_key_is_valid(void)
{
    uint8_t ret = s_key_valid;
    s_key_valid = 0;
    return ret;
}

#if FSL_SINGLE_KEY_INDICATE_MODE == FSL_SINGLE_KEY_INDICATE_BRIEF
/*
 * 函数说明
 */
void fsl_single_key_register_indicate_callback(void (*cb)(void))
{
    key_indicate_callback = cb;
}
#endif
